﻿using System.Collections.Generic;
using Godot.core;

namespace Godot.modules.gdscript
{
    public class GDScript : Script
    {
        
        internal Dictionary<StringName, GDScript> _subclasses;
        internal SortedSet<StringName> _members;
        internal Dictionary<StringName, Variant> _constants;
        internal Dictionary<StringName, GDFunction> _member_functions;
        internal Dictionary<StringName, int> _member_indices; //members are just indices to the instanced script.
        internal Dictionary<StringName, PropertyInfo> _member_info;
        internal SortedSet<Object> _instances;
        internal GDNativeClass _native;
        internal GDScript _basescr;
        internal GDScript _owner;
        internal GDScript _base;
        internal GDFunction _initializer;
        internal string _source;
        internal string _path;
        internal string _name;
        internal bool _valid;
        internal bool _tool;

        public GDScript()
        {
            _subclasses = new Dictionary<StringName, GDScript>(/*Comparer here*/);
        }

        public override bool has_source_code()
        {
            return (_source.Length != 0) ;
        }

        public override string get_source_code()
        {
            return _source;
        }

        public override void set_source_code(string p_code)
        {
            _source = p_code;
        }

        public override Error reload()
        {
            if(_instances.Count != 0)
                return Error.ERR_ALREADY_IN_USE;

	        string basedir = _path;

	        if (basedir == "")
		        basedir = this.get_path();

	        if (basedir != "")
		        basedir = basedir.get_base_dir();

	        _valid = false;
	        
            GDParser parser = new GDParser();
	        Error err = parser.parse(_source, basedir);
	        
            if (err != null) 
            {
		        //if (ScriptDebugger::get_singleton()) {
			    //    GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),parser.get_error_line(),"Parser Error: "+parser.get_error());
		        //}
		        //_err_print_error("GDScript::reload",path.empty()?"built-in":(const char*)path.utf8().get_data(),parser.get_error_line(),("Parse Error: "+parser.get_error()).utf8().get_data());
		        return Error.ERR_PARSE_ERROR;
	        }

	        GDCompiler compiler = new GDCompiler(); 
	        err = compiler.compile(parser, this);

	        if (err != null) 
            {
		        //if (ScriptDebugger::get_singleton()) {
			    //    GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),compiler.get_error_line(),"Parser Error: "+compiler.get_error());
		        //}
		        //_err_print_error("GDScript::reload",path.empty()?"built-in":(const char*)path.utf8().get_data(),compiler.get_error_line(),("Compile Error: "+compiler.get_error()).utf8().get_data());
		        return Error.ERR_COMPILATION_FAILED;
	        }

	        _valid = true;

            foreach(KeyValuePair<StringName, GDScript> E in _subclasses)
            {
		        _set_subclass_path(E.Value, get_path());
	        }

	        return Error.OK;
        }

        private void _set_subclass_path(GDScript p_sc, string p_path) 
        {
	        p_sc._path = p_path;
            foreach(KeyValuePair<StringName, GDScript> E in _subclasses)
            {
		        _set_subclass_path(E.Value,p_path);
	        }
        }

        public Variant new_instance(Variant[] p_args, Variant.CallError r_err)
        {
            return null;
        }

        public override bool is_tool
        {
            get { throw new System.NotImplementedException(); }
        }

        public override string get_node_type()
        {
            throw new System.NotImplementedException();
        }

        public override ScriptLanguage get_language()
        {
            return GDScriptLanguage.singleton;
        }

        public override bool can_instance()
        {
            throw new System.NotImplementedException();
        }

        public override StringName get_instance_base_type()
        {
            throw new System.NotImplementedException();
        }

        public override ScriptInstance instance_create(Object p_this)
        {
            throw new System.NotImplementedException();
        }

        public override bool instance_has(Object p_this)
        {
            throw new System.NotImplementedException();
        }
    }
}
